package com.broada.apm.indicator.api.model;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;

public class SearchCondition {
	private List<String> fields = new ArrayList<String>();
	private List<SearchConditionItem> items = new ArrayList<SearchConditionItem>();
	private List<AbstractAggregationBuilder> aggregations = new ArrayList<AbstractAggregationBuilder>();
	/**
	 * 默认运算符为AND 只支持单一运算符
	 */
	private SearchConditionOperator operator = SearchConditionOperator.AND;
	private String sortField;
	private String sortDirection;
	private int pageIndex;
	private int pageSize;
	private int defaultSize = 10;
	private String defaultSort = "ASC";
	private QueryBuilder queryBuilder;// 支持自定义queryBuilder
	private List<SearchCondition> childCondition = new ArrayList<SearchCondition>();

	private SearchCondition() {
	}

	public static SearchCondition newBuilder() {
		return new SearchCondition();
	}
	
	public SearchCondition add(SearchCondition searchCondition) {
		this.childCondition.add(searchCondition);
		return this;
	}

	public SearchCondition add(String field, SearchConditionComparator comparator, Object value, Object value_End) {
		this.items.add(new SearchConditionItem(field, comparator, value, value_End));
		return this;
	}

	public SearchCondition add(String field, SearchConditionComparator comparator) {
		this.items.add(new SearchConditionItem(field, comparator));
		return this;
	}

	public SearchCondition addOperator(SearchConditionOperator operator) {
		this.operator = operator;
		return this;
	}

	public SearchCondition addField(String field) {
		this.fields.add(field);
		return this;
	}

	public SearchCondition add(String field, SearchConditionComparator comparator, Object value) {
		this.items.add(new SearchConditionItem(field, comparator, value));
		return this;
	}

	public SearchCondition add(AbstractAggregationBuilder aggregationBuilder) {
		this.aggregations.add(aggregationBuilder);
		return this;
	}

	public List<SearchConditionItem> getConditionItems() {
		return this.items;
	}

	public String getSortDirection() {
		return StringUtils.isEmpty(this.sortDirection) ? defaultSort : this.sortDirection;
	}

	public SearchCondition setSortDirection(String sortDirection) {
		this.sortDirection = sortDirection;
		return this;
	}

	public int getPageIndex() {
		return pageIndex;
	}

	public int getStartRecord() {
		return pageIndex * pageSize;
	}

	public SearchCondition setPageIndex(int pageIndex) {
		this.pageIndex = pageIndex;
		return this;
	}

	public int getPageSize() {
		return pageSize == 0 ? defaultSize : pageSize;
	}

	public SearchCondition setPageSize(int pageSize) {
		this.pageSize = pageSize;
		return this;
	}

	public String getSortField() {
		return sortField;
	}

	public SearchCondition setSortField(String sortField) {
		this.sortField = sortField;
		return this;
	}

	public SearchConditionItem getConditionItem(String field) {
		for (Iterator<?> iterator = items.iterator(); iterator.hasNext();) {
			SearchConditionItem item = (SearchConditionItem) iterator.next();
			if (field.equals(item.getField()))
				return item;
		}
		return null;
	}

	public SearchConditionOperator getOperator() {
		return operator;
	}

	public List<AbstractAggregationBuilder> getAggregations() {
		return aggregations;
	}
	
	public List<String> getFields() {
		return fields;
	}

	/**
	 * 条件解析
	 * 
	 * @param searchCondition
	 */
	@SuppressWarnings("deprecation")
	public QueryBuilder parseCondition() {
		if (this.queryBuilder != null)
			return queryBuilder;
		
		ArrayList<QueryBuilder> queryBuilders = new ArrayList<>();
		// 处理AND，OR多运算符
		ArrayList<QueryBuilder> childQueryBuilders = new ArrayList<>();
		for (SearchCondition searchCondition : this.childCondition) {
			parseConditionItem(searchCondition, childQueryBuilders);
			if (searchCondition.getOperator().equals(SearchCondition.SearchConditionOperator.OR)) {
				queryBuilders.add(QueryBuilders.orQuery(childQueryBuilders.toArray(new QueryBuilder[childQueryBuilders.size()])));
			} else {
				queryBuilders.add(QueryBuilders.andQuery(childQueryBuilders.toArray(new QueryBuilder[childQueryBuilders.size()])));
			}
		}
		parseConditionItem(this, queryBuilders);

		if (this.getOperator().equals(SearchCondition.SearchConditionOperator.OR))
			return QueryBuilders.orQuery(queryBuilders.toArray(new QueryBuilder[queryBuilders.size()]));
		return QueryBuilders.andQuery(queryBuilders.toArray(new QueryBuilder[queryBuilders.size()]));
	}
	
	@SuppressWarnings("deprecation")
	private void parseConditionItem(SearchCondition searchCondition, ArrayList<QueryBuilder> queryBuilders) {
		for (Iterator<?> iterator = searchCondition.getConditionItems().iterator(); iterator.hasNext();) {
			SearchConditionItem item = (SearchConditionItem) iterator.next();
			if (item.getComparator().equals(SearchConditionComparator.EQUALS)) {
				if (StringUtils.endsWithIgnoreCase("id", item.getField())) {
					queryBuilders.add(QueryBuilders.idsQuery().addIds(new String[] { (String) item.getValue() }));
				} else {
					queryBuilders.add(QueryBuilders.termQuery((item.getField()), item.getValue()));
				}
			}
			if (item.getComparator().equals(SearchConditionComparator.NOTEQUALS)) {
				if (StringUtils.endsWithIgnoreCase("id", item.getField())) {
					queryBuilders.add(QueryBuilders.notQuery(QueryBuilders.idsQuery().addIds(
							new String[] { (String) item.getValue() })));
				} else {
					queryBuilders.add(QueryBuilders.notQuery(QueryBuilders.termQuery((item.getField()), item.getValue())));
				}
			}
			if (item.getComparator().equals(SearchConditionComparator.LEFTBETWEEN))
				queryBuilders.add(QueryBuilders.rangeQuery(item.getField()).gte(item.getValue()).lt(item.getValue_End()));
			if (item.getComparator().equals(SearchConditionComparator.RIGTHBETWEEN))
				queryBuilders.add(QueryBuilders.rangeQuery(item.getField()).gt(item.getValue()).lte(item.getValue_End()));
			if (item.getComparator().equals(SearchConditionComparator.BETWEEN))
				queryBuilders.add(QueryBuilders.rangeQuery(item.getField()).gt(item.getValue()).lt(item.getValue_End()));
			if (item.getComparator().equals(SearchConditionComparator.ALLBETWEEN))
				queryBuilders.add(QueryBuilders.rangeQuery(item.getField()).gte(item.getValue()).lte(item.getValue_End()));
			if (item.getComparator().equals(SearchConditionComparator.ISNULL))
				queryBuilders.add(QueryBuilders.missingQuery(item.getField()).existence(true).nullValue(true));
			if (item.getComparator().equals(SearchConditionComparator.EXISTS))
				queryBuilders.add(QueryBuilders.existsQuery(item.getField()));
			if (item.getComparator().equals(SearchConditionComparator.PREFIX))
				queryBuilders.add(QueryBuilders.prefixQuery(item.getField(), (String) item.getValue()));
			if (item.getComparator().equals(SearchConditionComparator.GTE))
				queryBuilders.add(QueryBuilders.scriptQuery(new Script("doc['" + item.getField() +"'].value >="+item.getValue()+"")));
			if (item.getComparator().equals(SearchConditionComparator.LTE))
				queryBuilders.add(QueryBuilders.scriptQuery(new Script("doc['" + item.getField() +"'].value <="+item.getValue()+"")));
			if (item.getComparator().equals(SearchConditionComparator.GT))
				queryBuilders.add(QueryBuilders.scriptQuery(new Script("doc['" + item.getField() +"'].value >"+item.getValue()+"")));
			if (item.getComparator().equals(SearchConditionComparator.LT))
				queryBuilders.add(QueryBuilders.scriptQuery(new Script("doc['" + item.getField() +"'].value <"+item.getValue()+"")));
			
			if (item.getComparator().equals(SearchConditionComparator.LENGTH))
				queryBuilders.add(QueryBuilders.scriptQuery(new Script(String.format("doc['%s'].value.size() == %s", item.getField(),
						item.getValue()))));
			if (item.getComparator().equals(SearchConditionComparator.LIKE))
				queryBuilders.add(QueryBuilders.queryFilter(QueryBuilders.wildcardQuery(item.getField(),
						String.format("*%s*", item.getValue()))));
			if (item.getComparator().equals(SearchConditionComparator.IN)) {
				if (item.getValue()!=null) {
					if (StringUtils.endsWithIgnoreCase("id", item.getField())) {
						queryBuilders.add(QueryBuilders.idsQuery().addIds((String[]) item.getValue()));
					} else {
						queryBuilders.add(QueryBuilders.termsQuery(item.getField(), (Object[]) item.getValue()));
					}
				}
			}
			if (item.getComparator().equals(SearchConditionComparator.NOTIN)) {
				if (item.getValue()!=null) {
					if (StringUtils.endsWithIgnoreCase("id", item.getField())) {
						queryBuilders.add(QueryBuilders.notQuery(QueryBuilders.idsQuery().addIds((String[]) item.getValue())));
					} else {
						queryBuilders.add(QueryBuilders.notQuery(QueryBuilders.termsQuery(item.getField(), (Object[])item.getValue())));
					}
				}
			}
			if (item.getComparator().equals(SearchConditionComparator.QUERY_STRING)) {
				QueryStringQueryBuilder queryString = new QueryStringQueryBuilder(String.format("*%s*", item.getValue()));
				queryBuilders.add(QueryBuilders.queryFilter(queryString.field(item.getField().toString())));
		
			}
			if (item.getComparator().equals(SearchConditionComparator.QUERY_STRING_LIKE)) {
				QueryStringQueryBuilder queryString = new QueryStringQueryBuilder(String.format("%s", item.getValue()));
				queryBuilders.add(QueryBuilders.queryFilter(queryString.field(item.getField().toString())));
			}
		}
	}

	/**
	 * 运算符
	 * 
	 * @author Administrator Create By Jan 12, 2015 5:24:39 PM
	 */
	public enum SearchConditionOperator {
		AND, OR
	}
}